#pragma once
#include <qbprotocol/include/SSMsgStruct.h>
#include <qbprotocol/include/message.h>
#include <qbprotocol/include/rdProto.h>

#include <functional>
#include <set>
#include <vector>

#include "../qbtools.h"
#include "RequestNotifier.h"

typedef std::function<void(qb::proto::Message&, qb::SSRequestMsg*)> WrapReqFunc;

class MessageReceiver;
/// <summary>
/// 消息发送封装类
/// </summary>
class S_TOOL_EXPORT MessagePoster {
 public:
  /// <summary>
  /// 发送原始数据流
  /// </summary>
  /// <param name="connect_id"></param>
  MessagePoster(int connect_id = 0);

  /// <summary>
  /// 发送SSRequestMsg
  /// </summary>
  /// <param name="connect_id"></param>
  /// <param name="req">发送的消息体</param>
  /// <param name="func">该消息体封装成protoMessage的函数</param>
  MessagePoster(qb::SSRequestMsg* req, const WrapReqFunc& func,
                int connect_id = 0);

  /// <summary>
  /// 发送特定消息，refer CLoginGwVerifyTask::SendClientInfo
  /// </summary>
  /// <param name="pr">接收该消息返回数据的对象</param>
  /// <returns>成功：消息号；失败-1 </returns>
  int send(MessageReceiver* pr = nullptr) const;

  /// <summary>
  /// 发送原始数据，refer SSUserAccountManager::requestSystime
  /// </summary>
  /// <param name="buf">The buf.</param>
  /// <param name="iLen">Length of the i.</param>
  /// <param name="msgType">Type of the MSG.</param>
  /// <returns>发送字节数</returns>
  int send(char* buf, int iLen, int msgType = E_FID_SERVER_QPID) const;

 private:
  int m_connect_id = 0;
  qb::SSRequestMsg* m_req = nullptr;
  WrapReqFunc m_reqWrapFunc = nullptr;
};

/// <summary>
/// 消息接收封装类，要接受消息的widget继承此类
/// </summary>
class S_TOOL_EXPORT MessageReceiver {
 public:
  MessageReceiver() = default;
  virtual ~MessageReceiver();

  /// <summary>
  /// 无需手动调用
  /// </summary>
  /// <param name="v"></param>
  void addReqs(int v) { m_reqs.insert(v); }

  /// <summary>
  /// 注册需要接收的推送消息
  /// </summary>
  /// <param name="pmi">推送消息信息：消息号，参数，填充参数的函数</param>
  /// <param name="req">注册推送的消息</param>
  /// <param name="fun">封装消息到protoMessage的函数</param>
  void registPush(const PushMsgInfo& pmi, qb::SSRequestMsg* req = nullptr,
                  const WrapReqFunc& fun = nullptr);

  void unRegistPush(const PushMsgInfo& pmi, qb::SSRequestMsg* req = nullptr,
                    const WrapReqFunc& fun = nullptr);

  /// <summary>
  /// 数据接受回调函数，注意:此函数在非UI线程！不要在此函数内做耗时操作!
  /// 此函数内要注意使用成员变量的问题，因为锁加在基类的析构函数内，子类析构的时候，可能onDataArrived正在被调用！！！
  /// 理想的方案：MessageReceiver使用shared_ptr的方式保存在RequestNotifier中，保证onDataArrived时，析构函数未被调用
  /// </summary>
  /// <param name="msg">返回数据</param>
  /// <comments>不能是纯虚函数，否则子类析构后，会导致调用异常；</comment>
  virtual void onDataArrived(const qb::SSAckMsg& msg) {}

 private:
  std::set<int> m_reqs;
  std::set<PushMsgInfo> m_pushes;
};
